
package com.capgemini.fs.app.ekms.persistence.dao.implementations;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.capgemini.fs.app.ekms.model.Entity;
import com.capgemini.fs.app.ekms.model.User;
import com.capgemini.fs.app.ekms.persistence.dao.BaseDAO;

public abstract class BaseDAOHibernateImpl<T> extends HibernateDaoSupport
		implements BaseDAO<T> {

	final static Logger	logger	= Logger.getLogger(User.class.getName());

	private enum SessionAction {
		Save, Update, Delete
	}

	@SuppressWarnings("unchecked")
	public T findByPrimaryKey(Class<?> clazz, Serializable id) {
		HibernateTemplate template = getHibernateTemplate();
		return (T) template.get(clazz, id);
	}

	public void delete(T t) {
		HibernateTemplate template = getHibernateTemplate();
		template.delete(t);
	}

	public void delete(final List<T> list) {
		this.batchProcessTemplate(list, SessionAction.Delete);
	}

	public void save(T t) {
		HibernateTemplate template = getHibernateTemplate();
		T instance = setEntityCreateAndUpdateTime(t);
		template.save(instance);
	}

	public void save(final List<T> list) {
		batchProcessTemplate(list, SessionAction.Save);
		// for(T t:list)
		// {
		// this.save(t);
		// }
	}

	public void saveOrUpdate(T t) {
		HibernateTemplate template = getHibernateTemplate();
		T instance = setEntityCreateAndUpdateTime(t);
		template.saveOrUpdate(instance);
	}

	public void update(T t) {
		HibernateTemplate template = getHibernateTemplate();
		T instance = setEntityCreateAndUpdateTime(t);
		template.update(instance);
	}

	public void update(final List<T> list) {
		// batchProcessTemplate(list, SessionAction.Update);
		for (T t : list) {
			this.update(t);
		}
	}

	@SuppressWarnings("unchecked")
	public T get(Class<?> clazz, Serializable id) {
		HibernateTemplate template = getHibernateTemplate();
		return (T) template.get(clazz, id);
	}

	public void evict(T t) {
		HibernateTemplate template = getHibernateTemplate();
		template.evict(t);
	}

	public void clear() {
		HibernateTemplate template = getHibernateTemplate();
		template.clear();
	}

	@SuppressWarnings("unchecked")
	public List<T> findAll(Class<?> clazz) {
		List<T> list = this.getHibernateTemplate().find(
				"from " + clazz.getName());
		// for (T t : list) {
		// getHibernateTemplate().evict(t);
		// }
		return list;
	}

	private T setEntityCreateAndUpdateTime(T t) {
		Entity entity = (Entity) t;
		Date createDate = entity.getCreateDate();

		if (null == createDate) {
			entity.setCreateDate(new Date());
		}

		entity.setLastUpdateDate(new Date());

		return t;
	}

	public void merge(T t) {
		HibernateTemplate template = getHibernateTemplate();
		template.merge(t);
	}

	public void refresh(T t) {
		HibernateTemplate template = getHibernateTemplate();
		template.refresh(t);
	}

	private void batchProcessTemplate(final List<T> list,
			final SessionAction action) {
		HibernateTemplate template = getHibernateTemplate();
		template.execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				for (int i = 0; i < list.size(); i++) {

					try {
						Method method = session.getClass().getDeclaredMethod(
								action.name().toLowerCase(), Object.class);
						method.invoke(session, list.get(i));
					} catch (Exception e) {
						logger.error("Exception : " + e);
						e.printStackTrace();
						throw new HibernateException(e);
					}

					if (0 == i % 15) {
						session.flush();
						session.clear();
					}
				}
				return list;
			}
		});

	}
}
